// PImage img; 
PImage img_sprite;// image du personnage
PImage img_tir;// image du tir
PImage BackGround; // image de fond
PImage img_level; // image servant à afficher le niveau
PImage img_levelTexture;
int PosX;        // Position sur l'axe des abscisses du personnage
int PosY;        // Position sur l'axe des ordonnées du personnage
int vitesse =5;  // vitesse de déplacement du personnage dans le jeu, se déplace de 5 pixels à chaque appui sur une touche
// définition de l'étape dans laquelle se trouve l'animation (valuer de 0 à 4 car 5 sprites par animations)
int nbSprite = 0;
int nbSpriteUP = 4;
int nbSpriteDOWN = 4;
int nbSpriteRIGHT = 4;
int nbSpriteLEFT = 4;
// tableau des coordonnées des sprites
int[][] dataSpriteRight; 
int[][] dataSpriteLeft;
int[][] dataSpriteUp;
int[][] dataSpriteDown;
// taille des sprites qui sont utilisés
int tailleXSprite = 19;
int tailleYSprite = 30;
// sert à définir le premier dessin du personnage (regarde vers la droite)
char lastMove = 'D';
// déclaration de l'objet Bomber de class Bomberman
Bomberman Bomber = new Bomberman(0,height/2-tailleYSprite);
Level Niveau = new Level(1,10,640,true);
//déclaration de la phase du jeu
int PhaseJeu = 0; 
// 0 = phase de début en attente d'appuie sur entrée
// 1 = phase de jeu
// 2 = game Over
// 3 = success

//gestion des points en fonction des monstres tués??

// Variable de gestion du tir
int maxTirs = 20;
int PosXTir;
int vitesseTir = 20;
// fait un tableau permettant de tirer 20 fois
Tir zeTir[] = new Tir[maxTirs];
int tirEnCours = 1;

// gestion de l'appui sur de multiple touche par un tableau
boolean[] keys=new boolean[5];
int CharZ=0;
int CharQ=1;
int CharS=2;
int CharD=3;
int CharSpace=4;




void setup() {
  // initialisation du tableau des touches
  keys[CharZ]=false;
  keys[CharQ]=false;
  keys[CharS]=false;
  keys[CharD]=false;
  keys[CharSpace]=false;
  definirTirs(maxTirs);
  for (int j=0; j < maxTirs; j++)  {
  // initialise tous les tirs à invisible
  zeTir[j].visible = false;
  }
  chargerSpriteBomber();
  // nombre d'image de l'animation
  frameRate(25);
  // taille de l'animation, rendra accessible les variables width et height
  size(640, 360); 
  //chargement de l'image qui servira de fond d'écran
  // cette image doit avoir la même taille que l'animation
  BackGround = loadImage("BG_voieLacte.jpg");
  img_level = loadImage("level.png");
  
  background(BackGround);
  
  // chargement d'une image du personnage VERSION TEST
  // img = loadImage("Bomberman.png");  // Load the image
  // chargement de l'image qui permettra d'avoir tous les sprites du personnage
  img_sprite = loadImage("BombermanSprite.png");
  //position initiale du personnage
  PosX = 0;
  PosXTir = 0;
  PosY = height/2-tailleYSprite;
  // sprite du tir
  img_tir = loadImage("miniufo.gif");
  // pour tester chacune des phases du jeu
  // PhaseJeu = 2;

}

void draw() {
  // répétition de l'instruction background afin de redessiner le fond à chaque draw
  background(BackGround);
  //background(255);
  if (PhaseJeu == 0){
  PFont zefonte; 
  zefonte = loadFont("AgencyFB-Reg-48.vlw");
    textFont(zefonte, 24); 
    text("Bienvenue",130,220);
    text("  " ,140,240);
    text("Appuyer sur S pour commencer\nPress S to reStart",150,260);
  if(keyPressed == true){
    switch(key){
    case 'S':
    case 's':
      PhaseJeu=1;
      break;
    }
  }
  }
  if (PhaseJeu == 1){
      //
      // algo simplifié tant que phase = 1
      // Définition du fond
      // chargement des images (Joueur, Mob, tracé parcours)
      //
      //recupere le coeficient de correction des coordonnes en fonction du déplacement du décor
    int coefCorrection = Niveau.deplacer();
    Niveau.afficher();
      /*if(keyPressed == true){
         switch(key){
            case 'z':
            case 'Z':
              nbSprite--;
              //déplacement vers le haut
              PosY=PosY-vitesse;
              //limitation du déplacement à la partie visible
              if (PosY <0)PosY=0;
              Bomber.deplacer('Z');
              lastMove='Z';
              break;
            case 's':
            case 'S':
              nbSprite++;
              //déplacement vers le bas
              PosY=PosY+vitesse;
              //limitation du déplacement à la partie visible
              if(PosY > height-tailleYSprite)PosY = height-tailleYSprite;
              Bomber.deplacer('S');
              lastMove='S';
              break;
            case 'q':
            case 'Q':
              nbSprite--;
              //déplacement vers la gauche
              PosX=PosX-vitesse;
              //limitation du déplacement à la partie visible
              if(PosX<0)PosX=0;
              Bomber.deplacer('Q');
              lastMove='Q';
              break;
            case 'd':
            case 'D':
              //déplacement vers la droite
              nbSprite++;
              PosX=PosX+vitesse;
              //limitation du déplacement à la partie visible
              if(PosX> width-tailleXSprite)PosX= width-tailleXSprite;
        Bomber.deplacer('D');
              lastMove='D';
              break;  
           case ' ':
              // tir du personnage
              nbSprite = 4;
              //tirer tant que le nombre max de tir n'est pas atteint
              Bomber.tirer();
              //PosXTir = PosXTir+(vitesse*4);
              //image(img_tir,PosXTir,PosY,32,6,423,565,455,571);
              println("touche espace");
              break;
          }
          
    }*/
    Bomber.deplacer();
        for (int j=0; j < maxTirs; j++)  {
      // parcoure la liste des tirs et les affiche s'ils sont visibles 
      if (zeTir[j].visible == true) {
        zeTir[j].deplacer();
        zeTir[j].afficher();
        zeTir[j].testerCollisionDecor(coefCorrection);
        zeTir[j].testerCollisionMob();
      }
        }
    
    // permet de continuer à dessiner le personnage tant qu'aucune action n'est faite
    Bomber.afficher(lastMove);
    //instruction s'il y a eu collision entre le bomber et l'environement ou le bomber et un mob
    if (Bomber.testerCollisionDecor(coefCorrection))PhaseJeu = 2 ;
    //Bomber.testerCollisionDecor(coefCorrection);
    //keyReleased();
  }
  if (PhaseJeu == 2){
    // game over
PFont zefonte; 
zefonte = loadFont("AgencyFB-Reg-48.vlw");
      textFont(zefonte, 14); 
      text("...game over...",130,220);
      text(" score " ,140,240);
      text("   press Enter \nto reStart",150,260);
  if( keyCode ==ENTER)  
    {  
      PhaseJeu=1;
      PosX=0;
      PosY=150;
    }  
  }  
}

// gestion des touches utilisées
void keyPressed(){
     if( key =='Z' || key=='z') 
    {  
      keys[CharZ]=true;
    }
     if( key =='Q' || key =='q')  
    {
      keys[CharQ]=true;
    }
     if( key =='S' || key=='s')  
    {  
      keys[CharS]=true;
    }
     if( key =='D' || key=='d') 
    {
      keys[CharD]=true;
    }
     if( key ==' ') 
    {
      keys[CharSpace]=true;
    }
}
void keyReleased(){
     if( key =='Z' || key=='z') 
    {  
      keys[CharZ]=false;
    }
     if( key =='Q' || key =='q')  
    {
      keys[CharQ]=false;
    }
     if( key =='S' || key=='s')  
    {  
      keys[CharS]=false;
    }
     if( key =='D' || key=='d') 
    {
      keys[CharD]=false;
    }
     if( key ==' ') 
    {
      keys[CharSpace]=false;
    }
}
// Fin de gestion des touches

class Bomberman  {
  int PositionDepartX;
  int PositionDepartY;
  int taille,numid;
  //float vitesse;
  float x, y, angle;
  boolean visible; 
  //constructeur
  //Bomberman(float xn, float yn, float anglen, float vitessen, int taillen, boolean visiblen, int numidn)  {
  Bomberman(int PositionDepartX,int PositionDepartY){
    this.x = PositionDepartX;
    this.y = PositionDepartY;
    //this.vitesse = vitessen;
    // this.visible = visiblen;
    }
    void tirer(){
    //boolean tirDone = false;
      zeTir[tirEnCours%maxTirs] = new Tir(PosX,PosY,true);
      tirEnCours ++ ;
    }
    void afficher(){
    if(nbSprite>4) nbSprite=0;
    image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteRight[nbSprite][0],dataSpriteRight[nbSprite][1],dataSpriteRight[nbSprite][0]+tailleXSprite,dataSpriteRight[nbSprite][1]+tailleYSprite);
    nbSprite++;
  }
    void afficher(char Move){
  // surcharge de la fonction afficher.  
  //utilisation d'un extrait du sprite bomberman
  //image(img,PosX,PosY,Width,Height,X,Y,W,H);
  // PosX,PosY,Width,Height: Position ou sera dessiner le sprite extrait
  // X,Y,W,H position dans le sprite
  // utilisation du sprite bomberman (partie de l'image)
  if(nbSprite>4) nbSprite=0;
  if(nbSprite<0) nbSprite=4;
  switch(Move){     
        case 'Z':
      //rect(PosX,PosY,tailleXSprite,tailleYSprite);
      image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteUp[nbSprite][0],dataSpriteUp[nbSprite][1],dataSpriteUp[nbSprite][0]+tailleXSprite,dataSpriteUp[nbSprite][1]+tailleYSprite);
      // déplacement vers le haut
      break;
        case 'S':
      //rect(PosX,PosY,tailleXSprite,tailleYSprite);
      image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteDown[nbSprite][0],dataSpriteDown[nbSprite][1],dataSpriteDown[nbSprite][0]+tailleXSprite,dataSpriteDown[nbSprite][1]+tailleYSprite);
      break;
        case 'Q':
      //rect(PosX,PosY,tailleXSprite,tailleYSprite);
          image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteLeft[nbSprite][0],dataSpriteLeft[nbSprite][1],dataSpriteLeft[nbSprite][0]+tailleXSprite,dataSpriteLeft[nbSprite][1]+tailleYSprite);
          break;
        case 'D':
    //rect(PosX,PosY,tailleXSprite,tailleYSprite);
        image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteRight[nbSprite][0],dataSpriteRight[nbSprite][1],dataSpriteRight[nbSprite][0]+tailleXSprite,dataSpriteRight[nbSprite][1]+tailleYSprite);
          break;
        default:
    //rect(PosX,PosY,tailleXSprite,tailleYSprite);
        image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteRight[nbSprite][0],dataSpriteRight[nbSprite][1],dataSpriteRight[nbSprite][0]+tailleXSprite,dataSpriteRight[nbSprite][1]+tailleYSprite);
          break;
    }
  
  // dessine et anime bomberman
  }
  void deplacer(){
      // gestion de l'appui multiple
    if( keys[CharZ]){  
      nbSprite--;
            //déplacement vers le haut
            PosY=PosY-vitesse;
            //limitation du déplacement à la partie visible
            if (PosY <0)PosY=0;
            //Bomber.deplacer('Z');
            lastMove='Z';
    }
    if( keys[CharQ]){
            nbSprite--;
            //déplacement vers la gauche
            PosX=PosX-vitesse;
            //limitation du déplacement à la partie visible
            if(PosX<0)PosX=0;
           // Bomber.deplacer('Q');
            lastMove='Q';
    }
    if( keys[CharS]){  
          nbSprite++;
            //déplacement vers le bas
            PosY=PosY+vitesse;
            //limitation du déplacement à la partie visible
            if(PosY > height-tailleYSprite)PosY = height-tailleYSprite;
          //  Bomber.deplacer('S');
            lastMove='S';
    }
    if( keys[CharD]){
            //déplacement vers la droite
            nbSprite++;
            PosX=PosX+vitesse;
            //limitation du déplacement à la partie visible
            if(PosX> width-tailleXSprite)PosX= width-tailleXSprite;
      //Bomber.deplacer('D');
            lastMove='D';
    }
    if( keys[CharSpace]){
            // tir du personnage
            nbSprite = 4;
            //tirer tant que le nombre max de tir n'est pas atteint
            Bomber.tirer();
            //PosXTir = PosXTir+(vitesse*4);
            //image(img_tir,PosXTir,PosY,32,6,423,565,455,571);
    }
    // Fin gestion des touche
  // boucle sur les sprites d'affichage pour ne jamais dépasser les limites
    if(nbSprite>4) nbSprite=0;
  if(nbSprite<0) nbSprite=4;
  /*switch(Move){     
        case 'Z':
          image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteUp[nbSprite][0],dataSpriteUp[nbSprite][1],dataSpriteUp[nbSprite][0]+tailleXSprite,dataSpriteUp[nbSprite][1]+tailleYSprite);
          // déplacement vers le haut
          break;
        case 'S':
          image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteDown[nbSprite][0],dataSpriteDown[nbSprite][1],dataSpriteDown[nbSprite][0]+tailleXSprite,dataSpriteDown[nbSprite][1]+tailleYSprite);
          break;
        case 'Q':
          image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteLeft[nbSprite][0],dataSpriteLeft[nbSprite][1],dataSpriteLeft[nbSprite][0]+tailleXSprite,dataSpriteLeft[nbSprite][1]+tailleYSprite);
          break;
        case 'D':
        image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteRight[nbSprite][0],dataSpriteRight[nbSprite][1],dataSpriteRight[nbSprite][0]+tailleXSprite,dataSpriteRight[nbSprite][1]+tailleYSprite);
          break;
        default:
        image(img_sprite,PosX,PosY,tailleXSprite,tailleYSprite,dataSpriteRight[nbSprite][0],dataSpriteRight[nbSprite][1],dataSpriteRight[nbSprite][0]+tailleXSprite,dataSpriteRight[nbSprite][1]+tailleYSprite);
          break;
   }*/
 }
  boolean testerCollisionDecor(int CoefCorrection){
    // comme le masque de collision est noir / transparent
    // utilisation de la fonction alpha pour trouver le pixel non transparent donc qui sont en collision
    //position du personnage dans le tableau de pixel de l'image
    
    int PositionPixel;
    int PositionTeste;
    boolean Collision = false;
    PositionPixel= (PosY * img_level.width) + PosX + CoefCorrection;
    PositionTeste = PositionPixel;
    // problème dans la taille de l'image, le tableau est plus grand que l'image
    img_level.loadPixels();
    // parcours tous les pixels du Bomber et vérifie la valeur de transparence des coordonnées dans img_level
    // 255 = collision
    // 0 = champs libre
    // permet de tester la collision dans un décor NON MOUVANT
    for( int i = 0; i < tailleYSprite; i++) {
      // boucle des lignes
      PositionTeste=PositionPixel+i*img_level.width;
      for ( int j = 0; j < tailleXSprite; j++) {
      // boucle des colonnes
        PositionTeste++;
        // !!! persiste un problème de outOfBound lorsque l'on teste les valeurs limites en MaxY
        if (alpha(img_level.pixels[PositionTeste])==255){
          //println("Collision");
          //permet de voir où les pixel sont testés en mettant gris
          //img_level.pixels[PositionTeste]=color(150);
          Collision = true;
        }
      }
      //img_level.pixels[PositionTeste]=0;
      img_level.updatePixels();
      //test de collision avec un monstre A FAIRE
    }
    return Collision;
  }
  boolean testerCollisionMob(int DeplacementDecorCol){
    // comme le masque de collision est noir / transparent
    // utilisation de la fonction alpha pour trouver le pixel non transparent donc qui sont en collision
    //position du personnage dans le tableau de pixel de l'image
    int PositionPixel;
    int PositionTeste;
    boolean Collision = false;
    PositionPixel= (PosY * img_level.width) + PosX;
    PositionTeste = PositionPixel;
    img_level.loadPixels();
    // parcours tous les pixels du Bomber et vérifie la valeur de transparence des coordonnées dans img_level
    // 255 = collision
    // 0 = champs libre
    // boucle à faire sur les mobs pour voir si les pixels du bomber touche les pixels du mob
      for( int i = 0; i < tailleYSprite; i++) {
        // boucle des lignes
        PositionTeste=PositionPixel+i*img_level.width;
        for ( int j = 0; j < tailleXSprite; j++) {
        // boucle des colonnes
          PositionTeste++;
          if (alpha(img_level.pixels[PositionTeste])==255){
            //println("Collision");
            //permet de voir ou les pixel sont testé
            img_level.pixels[PositionTeste]=0;
            Collision = true;
          }
        }
        img_level.pixels[PositionTeste]=0;
        img_level.updatePixels();
        //test de collision avec un monstre A FAIRE
      }
    return Collision;
  }
}
void chargerSpriteBomber(){
  //définition des coordonnées des sprites de bomberman
  // pour le déplacement à droite
  dataSpriteRight = new int[5][2];
  dataSpriteRight[0][0] = 5;
  dataSpriteRight[0][1] = 35;
  dataSpriteRight[1][0] = 26;
  dataSpriteRight[1][1] = 35;
  dataSpriteRight[2][0] = 47;
  dataSpriteRight[2][1] = 35;
  dataSpriteRight[3][0] = 67;
  dataSpriteRight[3][1] = 35;
  dataSpriteRight[4][0] = 86;
  dataSpriteRight[4][1] = 35;
  // sprite pour le déplacement à gauche
  dataSpriteLeft = new int[5][2];
  dataSpriteLeft[0][0] = 5;
  dataSpriteLeft[0][1] = 100;
  dataSpriteLeft[1][0] = 26;
  dataSpriteLeft[1][1] = 100;
  dataSpriteLeft[2][0] = 47;
  dataSpriteLeft[2][1] = 100;
  dataSpriteLeft[3][0] = 67;
  dataSpriteLeft[3][1] = 100;
  dataSpriteLeft[4][0] = 86;
  dataSpriteLeft[4][1] = 100;
  // sprite pour le déplacement vers le haut
  dataSpriteUp = new int[5][2];
  dataSpriteUp[0][0] = 5;
  dataSpriteUp[0][1] = 69;
  dataSpriteUp[1][0] = 26;
  dataSpriteUp[1][1] = 69;
  dataSpriteUp[2][0] = 47;
  dataSpriteUp[2][1] = 69;
  dataSpriteUp[3][0] = 67;
  dataSpriteUp[3][1] = 69;
  dataSpriteUp[4][0] = 86;
  dataSpriteUp[4][1] = 69;
  // sprite pour le déplacement vers le bas
  dataSpriteDown = new int[5][2];
  dataSpriteDown[0][0] = 5;
  dataSpriteDown[0][1] = 3;
  dataSpriteDown[1][0] = 26;
  dataSpriteDown[1][1] = 3;
  dataSpriteDown[2][0] = 47;
  dataSpriteDown[2][1] = 3;
  dataSpriteDown[3][0] = 67;
  dataSpriteDown[3][1] = 3;
  dataSpriteDown[4][0] = 86;
  dataSpriteDown[4][1] = 3;
}

void definirTirs(int n) {
 // création du tableau des tirs possible
  for (int j=0; j < n; j++) {
    zeTir[j] = new Tir(0,0,false);
  }
}

class Tir {
  
  int x, y; 
  int x1,y1,x2,y2; // coordonnées des sommets, utile pour les collisions
  int duree;
  boolean visible; 

  Tir(int xn, int yn,boolean visiblen)  {
    // point de départ du tir xn,yn
    this.x = xn;
    this.y = yn;
    this.visible = true;
  } 
  
  void afficher()  {
    if (this.visible = true){
    image(img_tir,this.x,this.y,32,6,423,565,455,571);
    }
  }
  
  void deplacer()  {
    // déplacement du tir sur la ligne X
    this.x = this.x + vitesseTir;
    //this.y = this.y + vitesseTir;
    // if (this.x < 0) this.x += width;
       
    // faire disparaitre si sort de l'écran
  // ne sera pas pris en compte dans la recherche de collision
  if (this.x > width) {
      this.visible = false;
    }
  }    
  
  boolean testerCollisionDecor(int coefCorrection) {
   // test de collision avec le décor
  int PositionPixel;
  int PositionTeste;
  boolean Collision = false;
  PositionPixel= (this.y * img_level.width) + this.x + coefCorrection;
  PositionTeste = PositionPixel;
  // problème dans la taille de l'image, le tableau est plus grand que l'image
  img_level.loadPixels();
  // parcours tous les pixels du Bomber et vérifie la valeur de transparence des coordonnées dans img_level
  // 255 = collision
  // 0 = champs libre
  // permet de tester la collision dans un décor NON MOUVANT
  for( int i = 0; i < img_tir.height; i++) {
    // boucle des lignes
    PositionTeste=PositionPixel+i*img_level.width;
    for ( int j = 0; j < img_tir.width; j++) {
    // boucle des colonnes
      PositionTeste++;
      // !!! persiste un problème de outOfBound lorsque l'on teste les valeurs limites en MaxY
      /*if (alpha(img_level.pixels[PositionTeste])==255){
        //println("Collision");
        //permet de voir où les pixel sont testés en mettant gris
        //img_level.pixels[PositionTeste]=color(150);
        Collision = true;
      }*/
    }
    //img_level.pixels[PositionTeste]=0;
    img_level.updatePixels();
  }
  return Collision;

  //test de collision avec un monstre
  }
  boolean testerCollisionMob(){
  return false;
  
  }
}

class Mob {
  float x, y, x1,x2; 
  boolean visible; 
  // constructeur
  Mob(float xn, float yn,boolean visiblen){
    // point de départ du monstre
    this.x = xn;
    this.y = yn;
    this.visible = true;
  }
  void afficher(){
    this.x1 = this.x + vitesseTir;
    this.x2 = this.x + vitesseTir;
    if (this.visible = true){
    // permet de voir s'il est dans le focus de la fenetre
    // sprite à redéfinir
    image(img_tir,this.x,this.y,32,6,423,565,455,571);
    }
  }
  void deplacer(char TypeMob){
    // déplacement du mob selon l'algo défini pour ce type
    this.x = this.x + vitesseTir;
    //this.y = this.y + vitesseTir;
     
    if (this.x < 0) this.x += width;

    if (this.x > width) {
      this.visible = false;
    }
  }    
}

class Level{
  // permettra de dessiner le level du jeu
  int LevelJeu;
  float x, y; 
  float x1,y1,x2,y2; // coordonnées des sommets, utile pour les collisions
  int duree;
  int VitesseNiveau = int(vitesse/2);
  // variable qui conservera le déplacement globale du décor par rapport à l'origine
  int DeplacementDecor = 0;

  // constructeur
  Level(int Leveln, int nbMonstres,int longeurNiveau, boolean worldBoss)  {
    // construction du level en fonction de l'argument donné au constructeur, du nombre de monstre,
    // de la longeur du niveau (en pixel) et de la présence d'un worlboss
    //position de départ
    x=0;
    y=0;
    }
 
   void afficher()  {
    // affiche une série de deux images du fond afin de faire croire à une continuité
    image(img_level,this.x%img_level.width,this.y,img_level.width,img_level.height);
    image(img_level,this.x%img_level.width+img_level.width,this.y,img_level.width,img_level.height);
    }
    
   int deplacer()  {
    // déplacement le parcours selon une vitesse VitesseNiveau vers la gauche
    // commenter cette ligne pour arrêter le défilement du décor
    this.x = this.x - VitesseNiveau;
    DeplacementDecor+=VitesseNiveau;
    DeplacementDecor=DeplacementDecor%img_level.width;
    
    //println(DeplacementDecor);
    return DeplacementDecor;
    }
 }
